home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Mac OS SDK / Dev.CD Jan 98 SDK2.toast / Development Kits (Disc 2) / TEC 1.2.1 / Sample Code / UnicodeHub / Convert.cp next >
Encoding:
Text File  |  1997-11-18  |  38.9 KB  |  1,131 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        Convert.cp
  3.  
  4.     Contains:    
  5.  
  6.     Version:    System 8
  7.  
  8.     Copyright:    © 1997 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     File Ownership:
  11.  
  12.         DRI:                Julio Gonzalez
  13.  
  14.         Other Contact:        Andrew Daniels
  15.  
  16.         Technology:            International
  17.  
  18.     Writers:
  19.  
  20.         (jag)    Julio Gonzalez
  21.  
  22.     Change History (most recent first):
  23.  
  24.          <3>     8/22/97    jag        Fix yet another bug in ResolveConversionParams. Also better
  25.                                     usage of TECFlush.
  26.          <2>     8/20/97    jag        Fix bug in ResolveConversionParams and set output handle length
  27.                                     appropriately in the Catch segment of DoConvert.
  28. */
  29.  
  30. #include "UnicodeHub.h"
  31. #include "UnicodeHubConstants.h"
  32.  
  33. #include <Sound.h>
  34. #include <Script.h>                            // Script Manager definitions
  35.  
  36. #include <LGrowZone.h>
  37. #include <LWindow.h>
  38. #include <PP_Messages.h>
  39. #include <PP_Resources.h>
  40. #include <PPobClasses.h>
  41. #include <UDrawingState.h>
  42. #include <UMemoryMgr.h>
  43. #include <UReanimator.h>
  44. #include <UDesktop.h>
  45. #include <URegistrar.h>
  46. #include <LEditField.h>
  47. #include <LTextEdit.h>
  48. #include <UTextTraits.h>
  49. #include <LDynamicArray.h>
  50.  
  51.  
  52.     /**********************************************************************************************************
  53.      *    TEC SPECIFIC CODE COMMENT
  54.      *
  55.      *    When using either the Text Encoding Converter or the Unicode Converter, it is wise to set a minimum output
  56.      *    buffer of 32 bytes.  Some conversions might convert a single element in one encoding to 32 bytes in the
  57.      *    other encoding.  32 bytes is currently the maximum that TEC with convert a single element to another
  58.      *    encoding.
  59.      **********************************************************************************************************/
  60. #define kMinimumBufferSize 32
  61.  
  62.     /**********************************************************************************************************
  63.      *    TEC SPECIFIC CODE COMMENT
  64.      *
  65.      *    NeedsTag inserts one of the language (CJK) character tags that we have placed in Apple's corporate zone.
  66.      *    We use it when we convert from Styled Text to Unicode in order to achieve Round Trip in our conversions.
  67.      *    If we know that the encoding we are about to convert is Chinese, Korean, or Japanese, then we insert
  68.      *    the appropriate tag in the Unicode stream.  Note, there are tags for both UTF-16 and UTF-8.
  69.      **********************************************************************************************************/
  70.  
  71. static void NeedsTag( StringPtr tag, TextEncoding  theEncoding, TextEncoding unicodeEncoding )
  72. {
  73.     TextEncodingBase    base=::GetTextEncodingBase( theEncoding );
  74.     
  75.     *tag=0;
  76.     
  77.     if( ::GetTextEncodingFormat(unicodeEncoding) == kUnicodeUTF8Format )
  78.     {        
  79.         switch( base )    //UTF-8 Tags
  80.         {
  81.             case    kTextEncodingMacJapanese:        tag[3]=0x9E; break;
  82.             case    kTextEncodingMacChineseTrad:    tag[3]=0x9D; break;
  83.             case    kTextEncodingMacKorean:            tag[3]=0x9F; break;
  84.             case    kTextEncodingMacChineseSimp:    tag[3]=0x9C; break;
  85.             default:                                tag[3]=0;
  86.         }
  87.         
  88.         if( tag[3] )
  89.         {
  90.             tag[0]=3;
  91.             tag[1]=0xEF;
  92.             tag[2]=0xA1;
  93.         }
  94.     }
  95.     else                    //UTF-16 Tags
  96.     {
  97.         switch( base )
  98.         {
  99.             case    kTextEncodingMacJapanese:        tag[2]=0x5E; break;
  100.             case    kTextEncodingMacChineseTrad:    tag[2]=0x5D; break;
  101.             case    kTextEncodingMacKorean:            tag[2]=0x5F; break;
  102.             case    kTextEncodingMacChineseSimp:    tag[2]=0x5C; break;
  103.             default:                                tag[2]=0;
  104.         }
  105.         
  106.         if( tag[2] )
  107.         {
  108.             tag[0]=2;
  109.             tag[1]=0xF8;
  110.         }
  111.     }
  112.     
  113. }
  114.     /**********************************************************************************************************
  115.      *    END TEC SPECIFIC CODE COMMENTED BLOCK
  116.      **********************************************************************************************************/
  117.  
  118.  
  119. // ---------------------------------------------------------------------------------
  120. //        • ResizeOutputHandle
  121. //        
  122. //        This function increase the size of a locked handle by resizeBy and will
  123. //        keep update a pointer into the handle if it happens to move after the resize
  124. //        We'll just this routine in the convert methods when we run out of buffer
  125. //        space and need to make room for more output
  126. // ---------------------------------------------------------------------------------
  127.  
  128. void ResizeOutputHandle( Handle h, char** outputPtr, ByteCount resizeBy );
  129. void ResizeOutputHandle( Handle h, char** outputPtr, ByteCount resizeBy )
  130. {
  131.     UInt32    oldSize=(UInt32)(*outputPtr) - (UInt32)(*h);
  132.     
  133.     ::HUnlock( h);
  134.     ::SetHandleSize( h, GetHandleSize( h) + resizeBy);
  135.     ThrowIfMemError_();
  136.     
  137.     ::HLock( h);
  138.     *outputPtr=(char*)( (UInt32)(*h) + oldSize);
  139. }
  140.  
  141. // ---------------------------------------------------------------------------------
  142. //        • ConvertFromMulti
  143. //        
  144. //        This method will convert Styled Text into a stream of Unicode.  Input is
  145. //        a text handle and a style record handle.  Based on each one of the runs
  146. //        found in the style handle, a conversion will take place from the appropriate
  147. //        text encoding derived from the script run to unicode.  Offsets into the 
  148. //        unicode stream will be kept so on output, we'll have a handle with a stream
  149. //        of unicode ( converted to hex - since we can't display Unicode directly
  150. //        yet :-)  and a offset array indicating were in the unicode stream the original
  151. //        script runs from the styled text occur.
  152. // ---------------------------------------------------------------------------------
  153.  
  154.  
  155. OSStatus
  156. CPPStarterApp::ConvertFromMulti(  TextEncoding unicodeEncoding, const Handle fromHexText, TEStyleHandle theStyle, UInt32 fromLen,
  157.                             Handle &toHexText, ByteCount &inputRead, ByteCount &outputLen,
  158.                              ByteCount &toLen, ByteOffset** &theOffsets,
  159.                              UInt32 toUnicodeFlags)
  160. {
  161.     TextToUnicodeInfo    textToUnicodeInfo;
  162.     OSStatus            status=noErr;
  163.     char*                input;
  164.     char*                output;
  165.     UnicodeMapping        mapping;
  166.     ByteCount            origOutputLen;
  167.     
  168.     inputRead=0;
  169.     outputLen=0;
  170.     toLen=0;
  171.     
  172.     UInt16    noRuns=(**theStyle).nRuns;
  173.     
  174.     //Create an array of offsets that is the same size as the number of runs in the styled text
  175.     //This offset array will be used by the caller to show how each run in the style run matches
  176.     //the Unicode stream. 
  177.     theOffsets=(ByteOffset**)NewHandle( noRuns * sizeof(ByteOffset) );
  178.     if( theOffsets == NULL )
  179.     {
  180.         status=MemError();
  181.         return status;
  182.     }
  183.     
  184.     /* Resize our output buffer if necessary to the minimum buffer we recommended earlier*/
  185.     outputLen=::GetHandleSize( toHexText );
  186.     if( outputLen < kMinimumBufferSize )
  187.     {
  188.         outputLen=kMinimumBufferSize;
  189.         ::SetHandleSize(toHexText, outputLen);
  190.     }
  191.     origOutputLen=outputLen;
  192.     
  193.     ::HLock( fromHexText);
  194.     input=*fromHexText;
  195.     
  196.     ::HLock( toHexText);
  197.     output=*toHexText;
  198.     
  199.  
  200.     //Fill out the unicode mapping structure with the appropriate version of Unicode ( UTF-8 or UTF-16)
  201.     mapping.unicodeEncoding = unicodeEncoding;
  202.     mapping.mappingVersion = kUnicodeUseLatestMapping;
  203.     
  204.     //loop for every one of the runs in our styled text and convert each run to Unicode
  205.     int i;
  206.     for(i=0; i<noRuns && status==noErr; i++) 
  207.     {
  208.         Str31            fontName;
  209.         unsigned char    tag[4];
  210.         
  211.         short    index=(**theStyle).runs[i].styleIndex;
  212.         
  213.     /**********************************************************************************************************
  214.      *    TEC SPECIFIC CODE COMMENT
  215.      *
  216.      *    In order to get an encoding for the specific run in the Styled Text, we call UpgradeScriptInfoToTextEncoding
  217.      *    with the font name only.  This is all we need to get an encoding.  We'll create our conversion context
  218.      *    based on this encoding
  219.      **********************************************************************************************************/
  220.         ::GetFontName( (*((**theStyle).styleTab))[index].stFont, fontName );
  221.         
  222.         /* If GetFontName fails by returning an empty font name ( possibly due to a bug in the Font itself ),
  223.             then call FontToScript and use the Script to derive the Text Encoding.  I've seen this bug
  224.             occur on Fonts present in older versions of the Hebrew Language Kit */
  225.         if( *fontName )
  226.             status=::UpgradeScriptInfoToTextEncoding( kTextScriptDontCare,
  227.                 kTextRegionDontCare, kTextLanguageDontCare, fontName, &mapping.otherEncoding);
  228.         else
  229.             status=::UpgradeScriptInfoToTextEncoding( ::FontToScript((*((**theStyle).styleTab))[index].stFont),
  230.                 kTextRegionDontCare, kTextLanguageDontCare, NULL, &mapping.otherEncoding);
  231.         if( status )
  232.             break;
  233.             
  234.             
  235.         status=::CreateTextToUnicodeInfo( &mapping, &textToUnicodeInfo );
  236.     /**********************************************************************************************************
  237.      *    END TEC SPECIFIC CODE COMMENTED BLOCK
  238.      **********************************************************************************************************/
  239.         if( !status )
  240.         {
  241.             ByteCount    oSourceRead=0;
  242.             ByteCount    oUnicodeLen=0;
  243.             
  244.             //assertain the input buffer length from the size of the style run
  245.             ByteCount    inputLen= ( i == noRuns-1 ? fromLen : (**theStyle).runs[i+1].startChar ) -
  246.                                 (**theStyle).runs[i].startChar    ;
  247.                                         
  248.     
  249.     
  250.             //figure out if we need a language tag.  If so, insert it in the output stream.
  251.             NeedsTag( tag, mapping.otherEncoding, unicodeEncoding );
  252.             if( *tag )
  253.             {
  254.                 if(*tag > outputLen )
  255.                 {
  256.                     ResizeOutputHandle( toHexText, &output, origOutputLen );
  257.                     outputLen+=origOutputLen;
  258.                 }
  259.                 
  260.                 ::BlockMove( tag+1, output, *tag );
  261.                 output+=*tag;
  262.                 outputLen-=*tag;
  263.             }
  264.             
  265.             
  266.             char*        oInput=input;
  267.             char*        oOutput=output;
  268.             
  269.     /**********************************************************************************************************
  270.      *    TEC SPECIFIC CODE COMMENT
  271.      *
  272.      *    Call ConvertFromTextToUnicode in a loop in the event that our output buffer is too small.  Each time
  273.      *    the call tells us that the buffer is too small, we just make the output buffer bigger by as much as it 
  274.      *    originally was.
  275.      **********************************************************************************************************/
  276.             do{
  277.                 ByteCount    tSourceRead, tUnicodeLen;
  278.                 
  279.                 status=::ConvertFromTextToUnicode( textToUnicodeInfo, 
  280.                                                 inputLen, oInput,
  281.                                                  toUnicodeFlags,
  282.                                                  0, NULL, NULL, NULL,
  283.                                                  outputLen, &tSourceRead, &tUnicodeLen, 
  284.                                                  (UniChar*)oOutput);
  285.                 if( status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr )
  286.                 {
  287.                     //Increase the size of the output buffer and update our input and output pointers
  288.                     
  289.                     ResizeOutputHandle( toHexText, &oOutput, origOutputLen );
  290.                     oOutput=(char*)( (UInt32)oOutput + tUnicodeLen);
  291.                     outputLen=origOutputLen+(outputLen-tUnicodeLen);
  292.  
  293.                     oInput=(char*)( (UInt32)oInput + tSourceRead);
  294.                     inputLen-=tSourceRead;
  295.                 }
  296.                 else
  297.                     outputLen-=tUnicodeLen;
  298.  
  299.                 
  300.                 oSourceRead+=tSourceRead;
  301.                 oUnicodeLen+=tUnicodeLen;
  302.  
  303.             }while( status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr );
  304.             
  305.     /**********************************************************************************************************
  306.      *    END TEC SPECIFIC CODE COMMENTED BLOCK
  307.      **********************************************************************************************************/
  308.  
  309.             //Now we have processed an entire run of text, so update our offsets accordingly
  310.             if( status == noErr || status == kTECUsedFallbacksStatus)
  311.             {
  312.             
  313.                 (*theOffsets)[i]=toLen;
  314.                 
  315.                 inputRead+=oSourceRead;
  316.                 toLen+=oUnicodeLen;    
  317.                 if( *tag )
  318.                     toLen+=*tag;
  319.                 
  320.                 input+=oSourceRead;
  321.                 output+=oUnicodeLen;
  322.                 
  323.                 
  324.                 status=noErr;
  325.             }
  326.             
  327.             
  328.             ::DisposeTextToUnicodeInfo( &textToUnicodeInfo );
  329.         }
  330.     
  331.  
  332.     }
  333.     
  334.     ::HUnlock( (Handle)toHexText );
  335.     ::SetHandleSize( (Handle)toHexText, toLen );
  336.     
  337.     outputLen=toLen;
  338.     
  339.     //This routine always shows the Unicode output stream in Hex, so go ahead an convert it
  340.         
  341.     if( toLen > 0 )
  342.     {
  343.         Handle    theHexText=::NewHandle(toLen*2);
  344.         ByteCount    destLen;
  345.         
  346.         if( theHexText )
  347.         {
  348.             HLock( toHexText);
  349.             HLock( theHexText);
  350.             BufToHex((StringPtr)*toHexText, (StringPtr)*theHexText, toLen, destLen, 0);
  351.             HUnlock( theHexText);
  352.         }
  353.         
  354.         ::DisposeHandle( toHexText );
  355.         toHexText=theHexText;
  356.         toLen*=2;
  357.         
  358.         ::HUnlock( fromHexText );
  359.         for(i=i-1; i>=0; i--)
  360.             (*theOffsets)[i]*=2;
  361.     }
  362.     
  363.     return status;
  364. }
  365.  
  366.     /**********************************************************************************************************
  367.      *    TEC SPECIFIC CODE COMMENT
  368.      *
  369.      *    This code tests to see if the encoding is Unicode.  The Block from 0x100 to 0x1FF has been currently
  370.      *    reserved for Unicode encodings.   In the future there is a small possibility that this might change.
  371.      *    If you require this type of functionality in your Apps, please notify us so that we may provide a 
  372.      *    suitable API for you to use.
  373.      **********************************************************************************************************/
  374. Boolean 
  375. CPPStarterApp::IsUnicode( TextEncoding encoding )
  376. {
  377.     TextEncoding    encodingBase=::GetTextEncodingBase( encoding );
  378.     
  379.     if( encodingBase >= kTextEncodingUnicodeDefault && encodingBase <= 0x01FF )
  380.         return true;
  381.     
  382.     return false;
  383. }
  384.     /**********************************************************************************************************
  385.      *    END TEC SPECIFIC CODE COMMENTED BLOCK
  386.      **********************************************************************************************************/
  387.  
  388. // ---------------------------------------------------------------------------------
  389. //        • ResolveConversionParams
  390. //        
  391. //        This method turns a selection from our pop up menus into the appropriate
  392. //        text encodings.  Later it determines which converter to use to perform the
  393. //        conversion.  Either the Unicode Converter or the Text Encoding Converter.
  394. //        Remember, this sample application code show cases the Unicode Converter.
  395. //        Hence, it tries to do as much as it can in the Unicode Converter.  This might
  396. //        not be wise in your own applications as the Text Encoding Converter might
  397. //        be able to perform a conversion more efficiently than the Unicode Converter.
  398. //        Especially if there exists a plugin that can go from encoding x to encoding y
  399. //        directly.  The Unicode Converter on the other hand has to use Unicode as
  400. //        a hub.  Wouldn't you rather get a direct flight to your destination? :-)
  401. // ---------------------------------------------------------------------------------
  402. void
  403. CPPStarterApp::ResolveConversionParams(    UInt32    fromEncodingIndex,  TextEncoding *fromTextEncoding,
  404.                                         UInt32     toEncodingIndex,     TextEncoding *toTextEncoding,
  405.                                         int        *converterToUse )
  406. {
  407.     OSStatus        status;
  408.     UnicodeMapping    findMapping;
  409.     UnicodeMapping    foundMapping;
  410.     ItemCount        oActualCount;
  411.  
  412.     findMapping.mappingVersion=kUnicodeUseLatestMapping;
  413.  
  414.     if( fromTextEncoding )
  415.     {    
  416.         if( fromEncodingIndex != 0 )
  417.             *fromTextEncoding = gTheApp->mAvailableMappings[ fromEncodingIndex-1 ];
  418.         else
  419.             *fromTextEncoding=kTextEncodingMultiRun;
  420.     }
  421.  
  422.     if( toTextEncoding )
  423.     {
  424.         if( toEncodingIndex != 0 )
  425.             *toTextEncoding = gTheApp->mAvailableMappings[ toEncodingIndex-1 ];
  426.         else
  427.             *toTextEncoding=kTextEncodingMultiRun;
  428.     }
  429.  
  430.     if( converterToUse == NULL || fromTextEncoding == NULL || toTextEncoding == NULL)
  431.         return;
  432.     
  433.     if( *fromTextEncoding == *toTextEncoding )
  434.     {
  435.         *converterToUse = kIllegalConverter;
  436.         return;
  437.     }
  438.     
  439.     if(  IsUnicode( *fromTextEncoding ) )     //if the from encoding is unicode but not UTF7 then return unicode converter
  440.     {                                        //otherwise return the high level converter
  441.         if( ( ::GetTextEncodingFormat( *fromTextEncoding ) == kUnicodeUTF7Format ) ||  IsUnicode( *toTextEncoding) )
  442.             *converterToUse = kHighLevelConverter;
  443.         else
  444.         {
  445.             *converterToUse = kUnicodeConverter;
  446.             
  447.             //Find out if the Unicode Converter can handle the destination encoding
  448.             if( *toTextEncoding != kTextEncodingMultiRun )
  449.             {
  450.                 findMapping.unicodeEncoding=*fromTextEncoding;
  451.                 findMapping.otherEncoding=*toTextEncoding;
  452.                 
  453.                 status = ::QueryUnicodeMappings(kUnicodeMatchOtherBaseMask | kUnicodeMatchOtherVariantMask | kUnicodeMatchOtherFormatMask, 
  454.                     &findMapping, 1, &oActualCount, &foundMapping);
  455.                 
  456.                 if( ( status != noErr && status != kTECArrayFullErr ) || ( oActualCount == 0 ) )
  457.                 {
  458.                     *converterToUse = kHighLevelConverter;
  459.                     return;
  460.                 }
  461.             }
  462.         }
  463.     }
  464.     else if(  IsUnicode( *toTextEncoding) )     //if the from encoding is unicode but not UTF7 then return unicode converter
  465.     {                                            //otherwise return the high level converter
  466.         if( ( GetTextEncodingFormat( *toTextEncoding ) == kUnicodeUTF7Format ) ||  IsUnicode( *fromTextEncoding) )
  467.             *converterToUse = kHighLevelConverter;
  468.         else    
  469.         {
  470.             *converterToUse = kUnicodeConverter;
  471.             
  472.             //Find out if the Unicode Converter can handle the destination encoding
  473.             if( *fromTextEncoding != kTextEncodingMultiRun )
  474.             {
  475.                 findMapping.unicodeEncoding=*toTextEncoding;
  476.                 findMapping.otherEncoding=*fromTextEncoding;
  477.                 
  478.                 status = ::QueryUnicodeMappings(kUnicodeMatchOtherBaseMask | kUnicodeMatchOtherVariantMask | kUnicodeMatchOtherFormatMask, 
  479.                     &findMapping, 1, &oActualCount, &foundMapping);
  480.                 
  481.                 if( ( status != noErr && status != kTECArrayFullErr ) || ( oActualCount == 0 ) )
  482.                 {
  483.                     *converterToUse = kHighLevelConverter;
  484.                     return;
  485.                 }
  486.             }
  487.         }
  488.     }
  489.     else
  490.     {
  491.         //We've determined that neither encoding is in Unicode so go ahead an determine if we can use the Unicode Converter
  492.         //as a Hub ( fromEncoding->Unicode->toEncoding ).
  493.         
  494.         
  495.         //If either encoding is a MultiRun, then we can't use either converter to do the job since the Unicode converter
  496.         //can only convert to/from Unicode and we have already determined that neither encoding is unicode.  The high
  497.         //level on the other hand supports MultiRun conversions but only from Unicode and this is already handled
  498.         //by the Unicode Converter.
  499.         if( ( *fromTextEncoding == kTextEncodingMultiRun ) || ( *toTextEncoding == kTextEncodingMultiRun ) )
  500.         {
  501.             *converterToUse = kIllegalConverter;
  502.             return;
  503.         }
  504.  
  505.         
  506.         findMapping.unicodeEncoding=kTextEncodingUnicodeDefault;
  507.         findMapping.otherEncoding=*fromTextEncoding;
  508.         
  509.         status = ::QueryUnicodeMappings(kUnicodeMatchOtherBaseMask | kUnicodeMatchOtherVariantMask | kUnicodeMatchOtherFormatMask, 
  510.             &findMapping, 1, &oActualCount, &foundMapping);
  511.         
  512.         if( ( status != noErr && status != kTECArrayFullErr ) || ( oActualCount == 0 ) )
  513.         {
  514.             *converterToUse = kHighLevelConverter;
  515.             return;
  516.         }
  517.         
  518.         findMapping.otherEncoding=*toTextEncoding;
  519.         
  520.         status = ::QueryUnicodeMappings(kUnicodeMatchOtherBaseMask | kUnicodeMatchOtherVariantMask | kUnicodeMatchOtherFormatMask, 
  521.             &findMapping, 1, &oActualCount, &foundMapping);
  522.         
  523.         if( ( status != noErr && status != kTECArrayFullErr ) || ( oActualCount == 0 ) )
  524.         {
  525.             *converterToUse = kHighLevelConverter;
  526.             return;
  527.         }
  528.         
  529.         *converterToUse = kUnicodeConverter;
  530.     }        
  531.  
  532.     
  533. }
  534.  
  535.  
  536.  
  537. // ---------------------------------------------------------------------------------
  538. //        • DoConvertToUnicode
  539. //          Converts a text stream from a specified encoding to Unicode
  540. // ---------------------------------------------------------------------------------
  541. OSStatus
  542. CPPStarterApp::DoConvertToUnicode( TextEncoding unicodeEncoding, UInt32 toUnicodeFlags, TextEncoding fromEncoding, Handle srcH,
  543.                                  ByteCount srcLen, Handle destH, ByteCount &inputRead, ByteCount &unicodeLen, ByteCount maxOutput)
  544. {
  545.     OSStatus            status;
  546.     TextToUnicodeInfo    textToUnicodeInfo;
  547.     UnicodeMapping        theMapping;
  548.     ByteCount            origOutputLen;
  549.  
  550.     
  551.     inputRead=0;
  552.     unicodeLen=0;
  553.     
  554.     
  555.     /* Resize our output buffer if necessary to the minimum buffer we recommended earlier*/
  556.     if( maxOutput < kMinimumBufferSize )
  557.     {
  558.         maxOutput=kMinimumBufferSize;
  559.         ::HUnlock(destH);
  560.         ::SetHandleSize(destH, maxOutput);
  561.         ::HLock(destH);
  562.     }
  563.     origOutputLen=maxOutput;
  564.  
  565.     char *src=*srcH;
  566.     char *dest=*destH;
  567.  
  568.     /* Create a unicodeMapping holding the specified source encoding and the target unicode encoding */
  569.  
  570.     theMapping.unicodeEncoding = unicodeEncoding;
  571.     theMapping.otherEncoding = fromEncoding;
  572.     theMapping.mappingVersion = kUnicodeUseLatestMapping;
  573.  
  574.     /* Create a conversion context from the specified mapping */
  575.     status=::CreateTextToUnicodeInfo( &theMapping, &textToUnicodeInfo);
  576.     
  577.     if( status )
  578.         Throw_(status);
  579.  
  580.  
  581.     /* Call ConvertFromTextToUnicode as many times as necessary to convert the whole input stream to unicode.
  582.         The output handle will get resized if necessary to accomodate the conversion of the whole input stream */
  583.     do{
  584.         ByteCount    tSourceRead, tUnicodeLen;
  585.         
  586.         status = ::ConvertFromTextToUnicode(textToUnicodeInfo, srcLen, (ConstLogicalAddress) src, toUnicodeFlags,
  587.                 0, nil, nil, nil, maxOutput, &tSourceRead, &tUnicodeLen, (UniCharArrayPtr)dest);
  588.  
  589.         //check to see if we need to adjust our output buffer size.  See discussion of this in ConvertFromMulti method.
  590.         if( status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr )
  591.         {
  592.             ResizeOutputHandle( destH, &dest, origOutputLen );
  593.             dest=(char*)( (UInt32)dest + tUnicodeLen);
  594.             maxOutput=origOutputLen+(maxOutput-tUnicodeLen);
  595.  
  596.             src=(char*)( (UInt32)src + tSourceRead);
  597.             srcLen-=tSourceRead;
  598.         }
  599.         
  600.         inputRead+=tSourceRead;
  601.         unicodeLen+=tUnicodeLen;
  602.  
  603.     }while( status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr );
  604.     
  605.     ::DisposeTextToUnicodeInfo( &textToUnicodeInfo );
  606.  
  607.     return status;
  608.  
  609. }
  610.  
  611.  
  612.  
  613. // ---------------------------------------------------------------------------------
  614. //        • DoConvertToMultiple
  615. //          Attempts to convert the input Unicode stream to a text stream composed
  616. //          of every single Mac OS Encoding ( derived from the Script ) that is 
  617. //          installed in the machine ( via Language Kits ).
  618. // ---------------------------------------------------------------------------------
  619. OSStatus
  620. CPPStarterApp::DoConvertToMultiple(     TextEncoding unicodeEncoding, UInt32 fromUnicodeFlags, TextEncodingRunHdl &theRuns, Handle srcH, ByteCount srcLen,
  621.                                 Handle destH, ByteCount &inputRead, ByteCount &outputLen, ByteCount maxOutput)
  622. {
  623.     OSStatus                status;
  624.     UnicodeToTextRunInfo    unicodeToTextRunInfo;
  625.     ItemCount                textEncodingRuns;
  626.     ItemCount                oTextEncodingRuns=0;
  627.     UnicodeMapping            mapping={0};
  628.     TextEncodingRunPtr        theRunsPtr;
  629.     ByteCount                origOutputLen;
  630.  
  631.     inputRead=0;
  632.     outputLen=0;
  633.  
  634.     /* Resize our output buffer if necessary to the minimum buffer we recommended earlier*/
  635.     if( maxOutput < kMinimumBufferSize )
  636.     {
  637.         maxOutput=kMinimumBufferSize;
  638.         ::HUnlock(destH);
  639.         ::SetHandleSize(destH, maxOutput);
  640.         ::HLock(destH);
  641.     }
  642.     origOutputLen=maxOutput;
  643.  
  644.     char *src=*srcH;
  645.     char *dest=*destH;
  646.  
  647.     /* Create a conversion context that maps from the specified version of unicode to 
  648.         every encoding that is currently installed in the system */ 
  649.     mapping.unicodeEncoding=unicodeEncoding;
  650.     status=::CreateUnicodeToTextRunInfo( 0, &mapping, &unicodeToTextRunInfo );
  651.     
  652.     if( status )
  653.         Throw_(status);
  654.     
  655.     /*    Create a handle to hold the text encoding runs that will be derived from converting the
  656.         Unicode stream into a set of Mac OS encoding runs.  Since I don't know what kind of text
  657.         I'm dealing with, but since this application is written to deal with small amounts of text,
  658.         I approximately allocate space for 1 run per every 20 characters of input. If this is
  659.         insufficient, I will adjust the size of the handle.  This is all in the code below.  For
  660.         your own Apps this allocation scheme will surely be flawed.  Especially if you are dealing
  661.         with a lot of text.  */
  662.     textEncodingRuns=( srcLen > 20 ? srcLen/10 : (srcLen > 10 ? srcLen/5 : 2) );
  663.     theRuns = (TextEncodingRunHdl)::NewHandle( sizeof(TextEncodingRun)*textEncodingRuns );
  664.     if( theRuns == 0 )
  665.         Throw_(MemError());
  666.  
  667.     ::HLock( (Handle)theRuns );
  668.     theRunsPtr=*theRuns;
  669.  
  670.     Boolean        ranOutOfSpace=false;
  671.     do{
  672.         ByteCount    tSourceRead, tUnicodeLen;
  673.         
  674.         status = ::ConvertFromUnicodeToTextRun(unicodeToTextRunInfo, srcLen,
  675.          (ConstUniCharArrayPtr) src, fromUnicodeFlags,
  676.                         0, nil, nil, nil, maxOutput, &tSourceRead, &tUnicodeLen, (LogicalAddress)dest,
  677.                         textEncodingRuns, &oTextEncodingRuns, theRunsPtr);
  678.  
  679.     /**********************************************************************************************************
  680.      *    TEC SPECIFIC CODE COMMENT
  681.      *
  682.      *    Here we handle a bit more complex case of kTECOutputBufferFullStatus than in the ConvertFromMulti method
  683.      *    above. The reason being that we need to check if we ran out of encoding run space and of just plain buffer
  684.      *    space.  Both cases are handled below.
  685.      **********************************************************************************************************/
  686.          ranOutOfSpace = (status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr || status == kTECArrayFullErr);
  687.         if( ranOutOfSpace )
  688.         {
  689.             //check to see if we ran out of encoding run buffer.  I know that if I get this error is the encoding run
  690.             //buffer because I did not make use of the offset array parameters in ConvertFromUnicodeToTextRun.  Had
  691.             //I done so, then I would have to check if I ran of offset buffer space, text encoding run buffer space,
  692.             //or both.
  693.             if( status == kTECArrayFullErr )
  694.             {    
  695.                 ResizeOutputHandle(  (Handle)theRuns, &((char*)theRunsPtr), (textEncodingRuns*sizeof(TextEncodingRun)) );
  696.                 
  697.                 maxOutput-=tUnicodeLen;
  698.             }
  699.             else    //it must have been that we ran out of buffer space.  NOTE, there is the possibility that
  700.             {        //we run out of both output buffer and encoding run buffer space.  That is unlikely, but if
  701.                     //it does happen to be the case, when we execute ConvertFromUnicodeToTextRun it will again
  702.                     //return a status error indicating that not enough buffer space for one or the other is
  703.                     //available, at that point we'll just adjust it.
  704.             
  705.                 ResizeOutputHandle( destH, &dest, origOutputLen );
  706.                 maxOutput=origOutputLen+(maxOutput-tUnicodeLen);
  707.             }
  708.             
  709.             dest=(char*)( (UInt32)dest + tUnicodeLen);
  710.             
  711.             src=(char*)( (UInt32)src + tSourceRead);
  712.             srcLen-=tSourceRead;
  713.         }
  714.         
  715.         //Adjust our encoding run array if this is not the first time we've gone through the loop.  We
  716.         //need to do this because ConvertFromUnicodeToTextRun encoding run offsets are zero based from
  717.         //the output stream it produces.  The second through nth time we call ConvertFromUnicodeToTextRun,
  718.         //the input/output streams are no longer zero based as far as the original caller to DoConvertToMultiple
  719.         //is concerned, so we need to adjust those offsets accordingly.
  720.         if( outputLen != 0 )
  721.         {
  722.             for( int runIndex=0; runIndex<oTextEncodingRuns; runIndex++)
  723.                 (theRunsPtr[runIndex]).offset+=outputLen;
  724.         }
  725.         
  726.         theRunsPtr+=oTextEncodingRuns;
  727.         
  728.         inputRead+=tSourceRead;
  729.         outputLen+=tUnicodeLen;
  730.  
  731.     }while( ranOutOfSpace );
  732.  
  733.     /**********************************************************************************************************
  734.      *    END TEC SPECIFIC CODE COMMENTED BLOCK
  735.      **********************************************************************************************************/
  736.  
  737.     
  738.     ::HUnlock( (Handle)theRuns );
  739.     ::SetHandleSize( (Handle)theRuns, ::GetHandleSize( (Handle)theRuns) - ( (textEncodingRuns-oTextEncodingRuns)*sizeof(TextEncodingRun) ) );
  740.     
  741.     ::DisposeUnicodeToTextRunInfo( &unicodeToTextRunInfo );
  742.  
  743.     return status;
  744.  
  745. }
  746.  
  747. // ---------------------------------------------------------------------------------
  748. //        • DoConvertToEncoding
  749. //        Converts a Unicode stream to a stream of text in the specified encoding
  750. // ---------------------------------------------------------------------------------
  751. OSStatus
  752. CPPStarterApp::DoConvertToEncoding(    TextEncoding unicodeEncoding, UInt32 fromUnicodeFlags, TextEncoding    toEncoding, Handle srcH, ByteCount srcLen,
  753.                                 Handle destH, ByteCount &inputRead, ByteCount &outputLen, ByteCount maxOutput)
  754. {
  755.     OSStatus            status;
  756.     UnicodeToTextInfo    unicodeToTextInfo;
  757.     UnicodeMapping        theMapping;
  758.     ByteCount            origOutputLen;
  759.  
  760.     
  761.     
  762.     inputRead=0;
  763.     outputLen=0;
  764.  
  765.     
  766.     /* Resize our output buffer if necessary to the minimum buffer we recommended earlier*/
  767.     if( maxOutput < kMinimumBufferSize )
  768.     {
  769.         maxOutput=kMinimumBufferSize;
  770.         ::HUnlock(destH);
  771.         ::SetHandleSize(destH, maxOutput);
  772.         ::HLock(destH);
  773.     }
  774.     origOutputLen=maxOutput;
  775.  
  776.     char *src=*srcH;
  777.     char *dest=*destH;
  778.  
  779.  
  780.     /* Create a unicodeMapping holding the specified source encoding and the target unicode encoding */
  781.  
  782.     theMapping.unicodeEncoding = unicodeEncoding;
  783.     theMapping.otherEncoding = toEncoding;
  784.     theMapping.mappingVersion = kUnicodeUseLatestMapping;
  785.     
  786.     /* Create a conversion context from the specified mapping */
  787.     status=::CreateUnicodeToTextInfo( &theMapping, &unicodeToTextInfo);
  788.     if( status )
  789.         Throw_(status);
  790.  
  791.     /* Call ConvertFromUnicodeToText as many times as necessary to convert the whole unicode stream.
  792.         The output handle will get resized if necessary to accomodate the conversion of the whole input stream */
  793.     do{
  794.         ByteCount    tSourceRead, tUnicodeLen;
  795.         
  796.         status = ::ConvertFromUnicodeToText(unicodeToTextInfo, srcLen, (ConstUniCharArrayPtr) src, fromUnicodeFlags,
  797.                         0, nil, nil, nil, maxOutput, &tSourceRead, &tUnicodeLen, (LogicalAddress)dest);
  798.  
  799.         //check to see if we need to adjust our output buffer size.  See discussion of this in ConvertFromMulti method.
  800.         if( status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr )
  801.         {
  802.             ResizeOutputHandle( destH, &dest, origOutputLen );
  803.             dest=(char*)( (UInt32)dest + tUnicodeLen);
  804.             maxOutput=origOutputLen+(maxOutput-tUnicodeLen);
  805.  
  806.             src=(char*)( (UInt32)src + tSourceRead);
  807.             srcLen-=tSourceRead;
  808.         }
  809.         
  810.         inputRead+=tSourceRead;
  811.         outputLen+=tUnicodeLen;
  812.  
  813.     }while( status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr );
  814.     
  815.     ::DisposeUnicodeToTextInfo( &unicodeToTextInfo );
  816.  
  817.     return status;
  818.  
  819. }
  820.  
  821.  
  822. // ---------------------------------------------------------------------------------
  823. //        • DoConvertUsingHLC
  824. //        Converts a text stream from one encoding to another using the Text Encoding
  825. //        Converter.
  826. // ---------------------------------------------------------------------------------
  827. OSStatus
  828. CPPStarterApp::DoConvertUsingHLC(    TextEncoding fromTextEncoding, Handle fromTextH, ByteCount fromTextLen,
  829.                                     TextEncoding toTextEncoding,  Handle toTextH, ByteCount toTextLen,
  830.                                      ByteCount &inputRead, ByteCount &outputLen )
  831. {
  832.     OSStatus        status;
  833.     TECObjectRef    newEncodingConverter;
  834.     ByteCount        origOutputLen;
  835.     Boolean            needsToFlush=true;
  836.     
  837.     inputRead=0;
  838.     outputLen=0;
  839.     
  840.     if( fromTextLen == 0 )
  841.         return noErr;
  842.         
  843.     /* Resize our output buffer if necessary to the minimum buffer we recommended earlier*/
  844.     if( toTextLen < kMinimumBufferSize )
  845.     {
  846.         toTextLen=kMinimumBufferSize;
  847.         ::HUnlock(toTextH);
  848.         ::SetHandleSize(toTextH, toTextLen);
  849.         ::HLock(toTextH);
  850.     }
  851.     origOutputLen=toTextLen;
  852.  
  853.     char *fromText=*fromTextH;
  854.     char *toText=*toTextH;
  855.  
  856.     /* Create a conversion object based on the source and destination encodings */
  857.     status = ::TECCreateConverter(&newEncodingConverter, fromTextEncoding,  toTextEncoding);
  858.     if( status )
  859.         Throw_(status);
  860.  
  861.     /**********************************************************************************************************
  862.      *    TEC SPECIFIC CODE COMMENT
  863.      *
  864.      *    Converting text using the Text Encoding Converter is no different than using the Unicode Converter.
  865.      *    However, there is one thing to watch out for.  That is, some converters may have some output left over
  866.      *    even when there is no more input to process.  So instead of calling TECConvertText, we call TECFlushText
  867.      *    to extract any other text that converter plugin may have in it's internal buffers.
  868.      **********************************************************************************************************/
  869.  
  870.     do{
  871.         ByteCount    tSourceRead, tUnicodeLen;
  872.         
  873.         /* If fromTextLen > 0 then we have some characters in the input stream which haven't been processed by
  874.             the converter, so call TECConvertText.  Otherwise, we've exhausted the input stream, so we just need
  875.             to flush out the rest of the converted stream from TEC's internal buffers.  Hence, we call  TECFlushText.
  876.             TECFlushText will be called at least once.  Could be called more depending on how much buffer space is left */
  877.         if( fromTextLen > 0 )
  878.             status = ::TECConvertText( newEncodingConverter, (ConstTextPtr) fromText,  fromTextLen, &tSourceRead, (TextPtr)toText,  toTextLen,  &tUnicodeLen);
  879.         else
  880.         {
  881.             status=::TECFlushText(newEncodingConverter, (TextPtr) toText, toTextLen, &tUnicodeLen);
  882.             needsToFlush=false;
  883.         }
  884.  
  885.         
  886.         if( fromTextLen > 0 )        //only adjust inputRead if not being called from TECFlushText
  887.             inputRead+=tSourceRead;
  888.             
  889.         outputLen+=tUnicodeLen;
  890.  
  891.         //check to see if we need to adjust our output buffer size.  This adjustment is no different from
  892.         //what we have seen in the Convert methods above.  We just take into consideration that we might
  893.         //be getting called from a TECFlushText so no adjustments need to be made for the input buffer
  894.         //or input length.
  895.         if( status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr )
  896.         {
  897.             ResizeOutputHandle( toTextH, &toText, origOutputLen );
  898.             toTextLen=origOutputLen+(toTextLen-tUnicodeLen);
  899.             
  900.             //It could happen that we set the needsToFlush flag to false prematurely, so reset it.
  901.             if(needsToFlush == false )
  902.                 needsToFlush=true;
  903.         }
  904.         else
  905.             toTextLen-=tUnicodeLen;
  906.  
  907.         toText=(char*)( (UInt32)toText + tUnicodeLen);
  908.         
  909.         if( fromTextLen > 0 )    //only adjust src/fromTextLen if not being called from TECFlushText
  910.         {
  911.             fromText=(char*)( (UInt32)fromText + tSourceRead);
  912.             fromTextLen-=tSourceRead;
  913.         }
  914.  
  915.     }while( status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr || needsToFlush);
  916.  
  917.  
  918.     /**********************************************************************************************************
  919.      *    END TEC SPECIFIC CODE COMMENTED BLOCK
  920.      **********************************************************************************************************/
  921.  
  922.     ::TECDisposeConverter( newEncodingConverter);
  923.  
  924.     return status;
  925.  
  926. }
  927.  
  928. // ---------------------------------------------------------------------------------
  929. //        • DoConvert
  930. //        
  931. //        This method gets called when a conversion needs to take place that isn't 
  932. //        Styled Text in origin.  It does not contain much Text Encoding Converter
  933. //        related features in it.  It is just a hub that serves to determine which
  934. //        conversion needs to take place.
  935. // ---------------------------------------------------------------------------------
  936.  
  937. OSStatus
  938. CPPStarterApp::DoConvert(    const Handle fromHexText, UInt32 fromLen, UInt32 fromEncoding,
  939.                             Handle toHexText, ByteCount &inputRead, ByteCount &outputLen, ByteCount &toLen, 
  940.                             UInt32 toEncoding, TextEncodingRunHdl &theRuns, 
  941.                             UInt32    fromUnicodeFlags, UInt32 toUnicodeFlags,
  942.                             Boolean wantHexOutput)
  943. {
  944.     volatile OSStatus    status=noErr;
  945.     volatile Handle        localFromText=0L;
  946.     volatile Handle        localToText=0L;
  947.  
  948.      EDebugAction    lDebugThrow=gDebugThrow;
  949.     EDebugAction    lDebugSignal=gDebugSignal;
  950.     
  951.     SetDebugThrow_(debugAction_Nothing);
  952.     SetDebugSignal_(debugAction_Nothing);
  953.  
  954.     Try_
  955.     {
  956.         Boolean        legalHexStr;
  957.         ByteCount    toHexLen;
  958.         ByteCount    localFromLen;
  959.         
  960.         TextEncoding    fromTextEncoding;
  961.         TextEncoding    toTextEncoding;
  962.         int                converterToUse;
  963.         
  964.         // Initialize some of our byte count output parameters
  965.         inputRead = 0;
  966.         outputLen = 0;
  967.         toLen=0;
  968.         
  969.         //Create a local fromText and use it to hold the from string consisting of the 
  970.         //converted hex string
  971.         
  972.         localFromText=::NewHandle( fromLen*2 );        
  973.         FailNIL_(localFromText);
  974.         
  975.         //Convert our string from Hex
  976.         ::HLock( fromHexText );
  977.         ::HLock( localFromText );
  978.         legalHexStr=FromHexToString( (StringPtr)*fromHexText, fromLen, (StringPtr)*localFromText, localFromLen );
  979.         if( !legalHexStr )
  980.         {
  981.             ::BlockMove( *fromHexText, *localFromText, fromLen );
  982.             localFromLen = fromLen;
  983.         }
  984.         
  985.         ::HUnlock( localFromText );
  986.         ::SetHandleSize( localFromText, localFromLen );
  987.         ::HLock( localFromText );
  988.  
  989.         ::HUnlock( fromHexText );
  990.         
  991.         toHexLen = ::GetHandleSize(toHexText);
  992.  
  993.         // Determine if the Unicode Converter can handle the input and output encodings.  If so, then use the Unicode
  994.         // Converter as a Hub to perform the conversion.  Otherwise, use the High Level Converter.
  995.         ResolveConversionParams( fromEncoding, &fromTextEncoding, toEncoding, &toTextEncoding, &converterToUse );
  996.         if( converterToUse == kUnicodeConverter )
  997.         {
  998.             //make a copy of the toText handle
  999.             localToText = toHexText;
  1000.             ::HandToHand(&localToText);
  1001.             ThrowIfMemError_();
  1002.             
  1003.             //Convert from encoding x to unicode -- if already unicode, just copy the string
  1004.             if( !IsUnicode(fromTextEncoding)    )
  1005.             {
  1006.                 TextEncoding    unicodeEncoding;
  1007.                 
  1008.                 ::HLock( localToText );
  1009.                 
  1010.                 unicodeEncoding =IsUnicode(toTextEncoding) ? toTextEncoding : kTextEncodingUnicodeDefault;
  1011.                 status=DoConvertToUnicode(    unicodeEncoding, toUnicodeFlags, 
  1012.                                             fromTextEncoding, localFromText, localFromLen,
  1013.                                             localToText, inputRead, outputLen, ::GetHandleSize(localToText));
  1014.                 fromTextEncoding = unicodeEncoding;
  1015.             }
  1016.             else
  1017.             {
  1018.                 ::HLock( localToText );
  1019.                 ::BlockMove( *localFromText, *localToText, localFromLen );
  1020.                 inputRead=0;
  1021.                 outputLen=localFromLen;
  1022.             }
  1023.             if(status && status!=kTECUsedFallbacksStatus)
  1024.                 Throw_( status );
  1025.                 
  1026.             //Convert from unicode to encoding x -- if already encoding x, just copy the string
  1027.             if( !IsUnicode( toTextEncoding)  )
  1028.             {
  1029.                 ::HLock( toHexText );
  1030.                 
  1031.                 if( toTextEncoding != kTextEncodingMultiRun  )
  1032.                     status=DoConvertToEncoding(    fromTextEncoding, fromUnicodeFlags, toTextEncoding, localToText, outputLen, toHexText,
  1033.                                             inputRead, outputLen, toHexLen);
  1034.                 else
  1035.                     status=DoConvertToMultiple( fromTextEncoding, fromUnicodeFlags, theRuns, localToText, outputLen, 
  1036.                                                     toHexText, inputRead, outputLen, toHexLen);
  1037.                 
  1038.                 ::BlockMove( *toHexText, *localToText, outputLen );
  1039.                 
  1040.                 toHexLen = ::GetHandleSize(toHexText);            //toHextText's size might have changed during the conversion process        
  1041.             }
  1042.             
  1043.         }
  1044.         else if( converterToUse == kHighLevelConverter )
  1045.         {
  1046.             //make a copy of the toText handle
  1047.             localToText = toHexText;
  1048.             ::HandToHand(&localToText);
  1049.             ThrowIfMemError_();
  1050.  
  1051.             ::HLock( localToText );
  1052.             
  1053.             status=DoConvertUsingHLC(    fromTextEncoding, localFromText, localFromLen,
  1054.                                         toTextEncoding, localToText, ::GetHandleSize(localToText), inputRead, outputLen);
  1055.                                         
  1056.         }
  1057.         else // converterToUse == kIllegalConverter
  1058.         {
  1059.             ::SetHandleSize( localToText, 0 );
  1060.             outputLen=0;
  1061.             inputRead=0;
  1062.             status=paramErr;
  1063.             ::ParamText("\pConversion requested is illegal or cannot be handled by this App","\p","\p","\p");
  1064.             ::Alert(kSimpleAlert, NULL);
  1065.         }
  1066.         
  1067.         if( wantHexOutput )
  1068.         {
  1069.             //When converting to Unicode, we will be converting the string to hex so that the hex representation
  1070.             //for 2 bytes is together plus a space separating it from the next 2 byte sequence.  When converting
  1071.             //to anything else, we will put a space between every byte.
  1072.             //Therefore, we need to figure out if we have enough space in our destination buffer.
  1073.             UInt8    clumpSize = (IsUnicode(toTextEncoding)) ? 2 : 1;
  1074.             UInt32    estOutputLen =  outputLen*2 + outputLen/clumpSize + outputLen%clumpSize ;
  1075.             if( toHexLen < estOutputLen )
  1076.             {
  1077.                 ::HUnlock( toHexText );
  1078.                 SetHandleSize( toHexText, estOutputLen );
  1079.                 ThrowIfMemError_();
  1080.                 
  1081.                 ::HLock( toHexText );
  1082.             }
  1083.             
  1084.             BufToHex( (StringPtr)*localToText, (StringPtr)*toHexText, outputLen, toLen, clumpSize );
  1085.  
  1086.             //Delete the runs handle since they don't make any sense in Hex
  1087.             if( theRuns )
  1088.             {
  1089.                 ::DisposeHandle( (Handle)theRuns );
  1090.                 theRuns=0;
  1091.             }
  1092.         }
  1093.         else
  1094.         {
  1095.             //resize the handle in the event that our outputLen is bigger or smaller
  1096.             ::HUnlock( toHexText );
  1097.             ::SetHandleSize( toHexText, outputLen );
  1098.             ::HLock( toHexText );
  1099.             
  1100.             ::BlockMove( *localToText, *toHexText, outputLen );
  1101.             toLen=outputLen;
  1102.         }
  1103.             
  1104.             
  1105.         if(status && status!=kTECUsedFallbacksStatus)
  1106.             Throw_(status);
  1107.         
  1108.         
  1109.     }
  1110.     Catch_(xErr)
  1111.     {
  1112.         ::SetHandleSize( toHexText, toLen );
  1113.         ::SysBeep(0);
  1114.         status = xErr;
  1115.     }
  1116.     EndCatch_
  1117.     
  1118.     if( localFromText )
  1119.         ::DisposeHandle(localFromText);
  1120.     if( localToText )
  1121.         ::DisposeHandle(localToText);
  1122.         
  1123.     ::HUnlock( toHexText );
  1124.     
  1125.     SetDebugThrow_(lDebugThrow);
  1126.     SetDebugSignal_(lDebugSignal);
  1127.         
  1128.     return status;
  1129. }
  1130.  
  1131.